import Vue from 'vue' // 默认导入
import App from './App.vue' // 根组件
import Vuex from 'vuex'

// Vue.use(VueRouter)

// 第一步，安装插件，实际调用 Vuex.install
Vue.use(Vuex)

// 第二步，创建 Vuex 仓库（store）实例
const store = new Vuex.Store({
  // 放状态/数据的
  state: {
    // 定义了一个状态，初始值为 0
    count: 0,
    list: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
  },
  // getters 就是 Vuex 的计算属性
  getters: {
    // 求过滤出来的 list 的元素之和
    sumOfFilterList(state, getters) {
      console.log('sumOfFilterList getter 函数调用了')
      // 如何在一个 getter 中访问其他的 getter？通过第二个参数 getters 可以获取到所有的 getter
      return getters.filterList.reduce((sum, v) => sum + v, 0)
    },
    doubleCount(state) {
      console.count('doubleCount 调用次数')
      return state.count * 2
    },
    filterList(state) {
      // filter 方法用来过滤数组元素，返回一个满足条件的元素组成的新数组
      return state.list.filter(v => v > 5)
    },
  },
  // 用来修改 state，只能写同步代码
  mutations: {
    // addCount: function () {}
    // 第一个形参：state，接收当前仓库的所有状态
    addCount(state) {
      state.count++
    },
    // 第二个形参：payload，是载荷，说人话，就是参数
    addCountN(state, payload) {
      state.count += payload
    },
    // addCountNN(state, payload) {
    // 传过来的 payload 是一个数组，那么就可以通过 数组形参解构 来一个个拿出来
    // addCountNN(state, [a, b, c, d]) {
    addCountNN(state, payload) {
      console.log(payload, 'payload')
      state.count += payload.reduce((sum, v) => sum + v, 0)
    },
  },
  actions: {
    // 第一个形参：context，当前的上下文仓库对象，说白了就是 store （当前模块的）
    // 第二个形参：payload，是载荷，说人话，就是参数，也不支持
    addCountAsync(context, [s, value]) {
      // 不规范，隐患：Vuex 中的状态毕竟是公共的，如果直接修改，那么变化就不受控制了，谁都能直接改，导致状态的管理混乱，通过 mutations 这个统一的修改入口，就可以集中控制
      // context.state.count += value
      // 怎么在 action 中调 mutation 呢？
      setTimeout(() => {
        context.commit('addCountN', value)
      }, s * 1000)
    },
  },
  // 子模块配置
  // 对于模块化而言，我们只要学一个子模块的访问方式就行了
  modules: {
    // 默认情况下，所有子模块的 getters/mutations/actions/modules 统统都会挂载到根模块上
    // 注意：上面的这个默认情况，其实不太推荐，有隐患（如果根模块上或者其他子模块上有同名的，那么就会起冲突）
    // 为了解决上面这个命名冲突的隐患，我们需要额外添加一个配置项：namespaced: true，这个配置项的默认值为 false，表示：默认不开启子模块的命名空间（说白了，就是不会互相隔离）
    // 这个 namespaced: true 墙裂推荐加上，大家无脑加上，以后只要定义了子模块，首先不要写 state/mutations/actions/getters，要首先写 namespaced: true
    /* 键：模块名称 */ child1: /* 值：子模块的配置 */ {
      // 注意：改为 true，之后，就开启了子模块的命名空间，那么子模块就有独立的空间了，和其他模块互相隔离了，getters/mutations/actions/modules 就不再挂载到根模块上了，那么，子模块的 getters/mutations/actions 的调用方式就发生了变化
      // namespaced: true,
      state: {
        a: 1,
      },
      mutations: {
        changeA(state, payload) {
          state.a = payload
        },
      },
      actions: {
        changeAAsync(ctx, payload) {
          setTimeout(() => {
            ctx.commit('changeA', payload)
          }, 1000)
        },
      },
      getters: {
        doubleA(state) {
          return state.a * 2
        },
      },
      // 一般不建议再次嵌套，会造成后期的维护和管理更复杂，违背了模块化的初衷
      // modules: {}
    },
    child2: {
      // 注意：改为 true，之后，就开启了子模块的命名空间，那么子模块就有独立的空间了，和其他模块互相隔离了，getters/mutations/actions/modules 就不再挂载到根模块上了，那么，子模块的 getters/mutations/actions 的调用方式就发生了变化
      // mutations ==> this.$store.commit('子模块名/mutation名', payload)
      // actions ==> this.$store.dispatch('子模块名/action名', payload)
      // getters ==> this.$store.getters['子模块名/getter名']
      namespaced: true,
      state: {
        a: 1,
      },
      mutations: {
        changeA(state, payload) {
          state.a = payload
        },
      },
      actions: {
        changeAAsync(ctx, payload) {
          setTimeout(() => {
            ctx.commit('changeA', payload)
          }, 1000)
        },
      },
      getters: {
        doubleA(state) {
          return state.a * 2
        },
      },
      // 一般不建议再次嵌套，会造成后期的维护和管理更复杂，违背了模块化的初衷
      // modules: {}
    },
  },
})

// const myPlugin = {
//   install(Vue) {
//     console.log(Vue, 'Vue的构造函数')
//   }
// }

// // 会调用这个 myPlugin.install 函数
// Vue.use(myPlugin)

Vue.config.productionTip = false

// Vue 根实例
new Vue({
  // 第三步，挂载到根实例上，和 Vue 建立联系
  // store: myStore,
  store,
  render: h => h(App),
}).$mount('#app')
